package cn.hloger.spider.demo.authDemo.interceptor;

import cn.hloger.spider.demo.authDemo.utils.SignUtils;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Enumeration;
import java.util.Map;

/**
 * 签名认证拦截器
 */
@Component
public class SignInterceptor implements HandlerInterceptor {


    /**
     * 接入系统标识
     */
    @Value("${accesskey:null}")
    private String accesskey;
    /**
     * aes密钥
     */
//    @Value("${secretkey}")
//    private String secretkey;


    private static final Logger logger = LoggerFactory.getLogger(SignInterceptor.class);

    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    @Override
    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
            throws Exception {
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
        if (HttpMethod.POST.name().equals(request.getMethod())) {
            Map<String, String> paramsMap = getPostFormData(request);
            checkAccessKey(paramsMap.get("access_key"));

            String url = request.getRequestURI();
            String sign = paramsMap.get("sign");
            String timestamp = paramsMap.get("timestamp");
            String requestId = paramsMap.get("request_id");
            checkSignIsValid(sign, timestamp, requestId);

            String biz_content = paramsMap.get("biz_content");
            try {
                boolean validPostRequest = SignUtils.isValidRequest(sign, biz_content, requestId,
                        timestamp, request.getMethod());
                if (!validPostRequest) {
                    writer(response, "签名无效");
                    logger.info("{}  认证失败 参数:sign = {} , url = {} ,请求参数 = {} , 配置的requestId = {} , timestamp ={}",
                            request.getMethod(),
                            sign,
                            url,
                            biz_content,
                            requestId,
                            "",
                            timestamp);
                    return false;
                }
                return true;
            } catch (Exception e) {
                e.printStackTrace();
                writer(response, "系统异常:" + e.getMessage());
                return false;
            }

        } else {
            writer(response, "请求方式必须为post");
        }
        return false;
    }

    private void checkAccessKey(String requestAccessKey) {
        if (StringUtils.isBlank(requestAccessKey)) {
            logger.info("签名认证失败：" + "接入系统标识不能为空");
            throw new IllegalArgumentException("接入系统标识不能为空");
        }
        if (!this.accesskey.equals(requestAccessKey)) {
            logger.info("签名认证失败：" + "接入系统标识错误");
            throw new IllegalArgumentException("接入系统标识错误");
        }
        return;
    }

    /**
     * 获取x-www-form-urlencoded 信息
     */
    private Map<String, String> getPostFormData(HttpServletRequest request) {
        Map<String, String> map = Maps.newHashMap();
        Enumeration<String> parameterNames = request.getParameterNames();
        while (parameterNames.hasMoreElements()) {
            String paramName = parameterNames.nextElement();
            String[] paramValues = request.getParameterValues(paramName);
            for (int i = 0; i < paramValues.length; i++) {
                String paramValue = paramValues[i];
                map.put(paramName, paramValue);
            }
        }
        return map;
    }

    private void writer(HttpServletResponse response, String restResult) {
        try {
            response.setContentType("application/json; charset=utf-8");
            response.setHeader("Cache-Control", "no-cache");
            response.setCharacterEncoding("utf-8");
            response.getWriter().write(restResult);
            response.getWriter().flush();
        } catch (Exception e) {
            e.printStackTrace();
        }
//        finally {
//            response.getWriter().close();
//        }
    }

    private String getUrlPram(HttpServletRequest request) {
        //form 表单请求的参数   xx.x?dd=1&b=2
        Enumeration<?> pNames = request.getParameterNames();
//                InputStream is = null;
//                is = request.getInputStream();
//                String bodyInfo = IOUtils.toString(is, "utf-8");
        StringBuffer sb = new StringBuffer();
        while (pNames.hasMoreElements()) {
            String pName = (String) pNames.nextElement();
//                    if ("signature".equals(pName)) continue;
            String pValue = (String) request.getParameter(pName);
            if (sb.length() == 0) {
                if (StringUtils.isNotBlank(pName)) {
                    sb.append(pName + "=" + pValue);
                }
            } else {
                if (StringUtils.isNotBlank(pName)) {
                    sb.append("&" + pName + "=" + pValue);
                }
            }
        }
        return sb.toString();
    }

    private void checkSignIsValid(String sign, String timestamp, String request_id) {
        if (StringUtils.isBlank(sign)) {
            logger.info("签名认证失败：" + "签名有误");
            throw new IllegalArgumentException("签名有误");
        }
        if (StringUtils.isBlank(timestamp)) {
            logger.info("签名认证失败：" + "时间戳不能为空");
            throw new IllegalArgumentException("时间戳不能为空");
        }
        if (StringUtils.isBlank(request_id)) {
            logger.info("签名认证失败：" + "requestId不能为空");
            throw new IllegalArgumentException("requestId不能为空");
        }
        return;
    }
}

